#pragma once

#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"


enum Level // 日志信息等级
{
    DEBUG = 0, // 调试信息
    INFO,      // 常规信息
    WARNING,   // 警告信息
    ERROR,     // 错误信息
    FATAL      // 严重问题
};

bool Save_File = false;                            // 标记是否把日志信息保存进文件中
const std::string logname = "log.txt";             // 保存日志信息的文件名
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 保护临界资源的锁---显示器、文件等

std::string LevelToString(int level) // 将日志等级转换为对应字符串
{
    switch (level)
    {
    case 0:
        return "DEBUG";
    case 1:
        return "INFO";
    case 2:
        return "WARNING";
    case 3:
        return "ERROR";
    case 4:
        return "FATAL";
    default:
        return "Unknow";
    }
}

std::string GetTimeString() // 获取时间并转换为字符串
{
    time_t cur_time = time(nullptr);               // 获取当前时间的时间戳
    struct tm *format_time = localtime(&cur_time); // 将时间戳转换为标准时间格式

    if (format_time == nullptr)
    {
        return "None";
    }

    char time_buffer[1024];
    strftime(time_buffer, sizeof(time_buffer) - 1, "%04Y-%02m-%02d %T", format_time);

    return time_buffer;
}

void SaveFile(std::string message)
{
    std::ofstream out(logname, std::ofstream::app); // 以追加模式打开日志文件。如果文件已经存在，新的内容将被追加到文件的末尾；如果文件不存在，则创建一个新文件。
    if (!out.is_open())                             // 日志文件没有打开
    {
        return;
    }

    out << message; // 向文件中写入信息
    out.close();
}

void LogMessage(std::string filename, int Line, bool savefile, int level, const char *format, ...) // 生成日志信息
{
    std::string levelstr = LevelToString(level); // 将日志等级转为对应字符串
    std::string timestr = GetTimeString();       // 获取当前时间并转为字符串返回
    pid_t id = getpid();

    // 解析可变参数
    char buffer[1024];
    va_list arg;
    va_start(arg, format);
    vsnprintf(buffer, sizeof(buffer), format, arg);
    va_end(arg);

    // 生产日志信息
    std::string message = "[" + levelstr + "]" + " " + "[" + timestr + "]" + " " +
                          "[" + std::to_string(id) + "]" + " " + "[" + filename + "]" + ":" +
                          "[" + std::to_string(Line) + "]" + " # " + buffer;

    LockGuard m(&mutex); // 加锁，防止信息混乱
    if (Save_File)
    {
        SaveFile(message);
    }
    else
    {
        std::cout << message;
    }
}
